home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / lfs / lfsSeg.c < prev    next >
C/C++ Source or Header  |  1991-08-08  |  53KB  |  1,854 lines

  1. /* 
  2.  * lfsSeg.c --
  3.  *
  4.  *    Handles the manipulation of LFS segments.
  5.  *
  6.  * Copyright 1989 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/kernel/lfs/RCS/lfsSeg.c,v 1.17 91/08/08 17:48:29 mendel Exp $ SPRITE (Berkeley)";
  18. #endif /* not lint */
  19.  
  20. #include <lfsInt.h>
  21. #include <lfsSeg.h>
  22. #include <stdlib.h>
  23. #include <sync.h>
  24. #include <fsStat.h>
  25.  
  26. #define    LOCKPTR    &lfsPtr->lock
  27.  
  28. int    lfsMinNumberToClean = 10;
  29.  
  30. Boolean    lfsSegWriteDebug = FALSE;
  31.  
  32. #define    MIN_SUMMARY_REGION_SIZE    16
  33.  
  34.  
  35. enum CallBackType { SEG_LAYOUT, SEG_CLEAN_IN, SEG_CLEAN_OUT, SEG_CHECKPOINT, 
  36.            SEG_WRITEDONE};
  37.  
  38. LfsSegIoInterface *lfsSegIoInterfacePtrs[LFS_MAX_NUM_MODS];
  39.  
  40.  
  41. static void SegmentCleanProc _ARGS_((ClientData clientData, 
  42.                      Proc_CallInfo *callInfoPtr));
  43. static LfsSeg *CreateSegmentToClean _ARGS_((Lfs *lfsPtr, int segNumber, 
  44.             char *cleaningMemPtr));
  45. static LfsSeg *CreateSegmentToWrite _ARGS_((Lfs *lfsPtr, Boolean dontBlock));
  46. static LfsSeg *GetSegStruct _ARGS_((Lfs *lfsPtr, LfsSegLogRange 
  47.             *segLogRangePtr, int startBlockOffset, char *memPtr));
  48. static void AddNewSummaryBlock _ARGS_((LfsSeg *segPtr));
  49. static Boolean DoOutCallBacks _ARGS_((enum CallBackType type, LfsSeg *segPtr, int flags, char *checkPointPtr, int *sizePtr, ClientData *clientDataPtr));
  50. static ReturnStatus WriteSegmentStart _ARGS_((LfsSeg *segPtr));
  51. static ReturnStatus WriteSegmentFinish _ARGS_((LfsSeg *segPtr));
  52. static void WriteDoneNotify _ARGS_((Lfs *lfsPtr));
  53. static void RewindCurPtrs _ARGS_((LfsSeg *segPtr));
  54. static Boolean DoInCallBacks _ARGS_((enum CallBackType type, LfsSeg *segPtr, int flags, int *sizePtr, int *numCacheBlocksPtr, ClientData *clientDataPtr));
  55. static void DestorySegStruct _ARGS_((LfsSeg *segPtr));
  56.  
  57. /*
  58.  * Macro returning TRUE if segment is completely empty.
  59.  */
  60. #define SegIsEmpty(segPtr) (((segPtr)->numBlocks == 1) &&         \
  61.         ((segPtr)->curSegSummaryPtr->size == sizeof(LfsSegSummary)))
  62.  
  63. /*
  64.  *----------------------------------------------------------------------
  65.  *
  66.  * -- LfsSegIoRegister
  67.  *
  68.  *    Register with the segment module an interface to objects in the log.   
  69.  *
  70.  * Results:
  71.  *    None.
  72.  *
  73.  * Side effects:
  74.  *    None.
  75.  *
  76.  *----------------------------------------------------------------------
  77.  */
  78.  
  79. void
  80. LfsSegIoRegister(moduleType, ioInterfacePtr)
  81.     int            moduleType; /* Module type registering. Type defined in
  82.                      * lfsSegWrite.h */
  83.     LfsSegIoInterface    *ioInterfacePtr;  /* Interface to use. */
  84.  
  85. {
  86.     lfsSegIoInterfacePtrs[moduleType] = ioInterfacePtr;
  87. }
  88.  
  89. /*
  90.  *----------------------------------------------------------------------
  91.  *
  92.  * LfsSegmentWriteProc --
  93.  *
  94.  *    Proc_CallFunc procedure for performing a segment writes.
  95.  *
  96.  * Results:
  97.  *    None.
  98.  *
  99.  * Side effects:
  100.  *    None.
  101.  *
  102.  *----------------------------------------------------------------------
  103.  */
  104.  
  105. /*ARGSUSED*/
  106.  void
  107. LfsSegmentWriteProc(clientData, callInfoPtr)
  108.     ClientData       clientData;
  109.     Proc_CallInfo *callInfoPtr;         /* Not used. */
  110. {
  111.     register Lfs *lfsPtr;            /* File system with dirty blocks. */
  112.     Boolean    full;
  113.     LfsSeg    *segPtr;
  114.     ClientData        clientDataArray[LFS_MAX_NUM_MODS];
  115.     int            i;
  116.     ReturnStatus    status;
  117.     Boolean        moreWork;
  118.  
  119.     lfsPtr = (Lfs *) clientData;
  120.     moreWork = TRUE;
  121.     while (moreWork) { 
  122.     full = TRUE;
  123.     for (i = 0; i < LFS_MAX_NUM_MODS; i++) {
  124.         clientDataArray[i] = (ClientData) NIL;
  125.     }
  126.     while (full) {
  127.         segPtr = CreateSegmentToWrite(lfsPtr, FALSE);
  128.         full = DoOutCallBacks(SEG_LAYOUT, segPtr, 0, (char *) NIL,
  129.                     (int *) NIL, clientDataArray);
  130.         status = WriteSegmentStart(segPtr);
  131.         if (status == SUCCESS) {
  132.         status = WriteSegmentFinish(segPtr);
  133.         }
  134.         if (status != SUCCESS) {
  135.         LfsError(lfsPtr, status, "Can't write segment to log\n");
  136.         }
  137.         RewindCurPtrs(segPtr);
  138.         (void) DoInCallBacks(SEG_WRITEDONE, segPtr, 0,
  139.                     (int *) NIL, (int *) NIL, clientDataArray);
  140.         WriteDoneNotify(lfsPtr);
  141.         DestorySegStruct(segPtr);
  142.     }
  143.     moreWork = LfsMoreToWriteBack(lfsPtr);
  144.     }
  145.     return;
  146. }
  147.  
  148.  
  149. /*
  150.  *----------------------------------------------------------------------
  151.  *
  152.  * LfsSegCleanStart --
  153.  *
  154.  *    Request that the segment manager start cleaning segments
  155.  *    for the specified file system.
  156.  *
  157.  * Results:
  158.  *    None.
  159.  *
  160.  * Side effects:
  161.  *    A segment cleaning process may be started.
  162.  *
  163.  *----------------------------------------------------------------------
  164.  */
  165.  
  166. void
  167. LfsSegCleanStart(lfsPtr)
  168.     Lfs     *lfsPtr;    /* File system needing segments cleaned. */
  169. {
  170.     LFS_STATS_INC(lfsPtr->stats.cleaning.startRequests);
  171.     if (lfsPtr->activeFlags & LFS_CLEANER_ACTIVE) {
  172.     LFS_STATS_INC(lfsPtr->stats.cleaning.alreadyActive);
  173.     return;
  174.     }
  175.     lfsPtr->activeFlags |= LFS_CLEANER_ACTIVE;
  176.     Proc_CallFunc(SegmentCleanProc, (ClientData) lfsPtr, 0);
  177. }
  178.  
  179. /*
  180.  *----------------------------------------------------------------------
  181.  *
  182.  * LfsSegSlowGrowSummary --
  183.  *
  184.  *    Insure that there is enought room for an object with the 
  185.  *    specified number of blocks and summary bytes. Possibly add a
  186.  *    new summary block if needed.
  187.  *
  188.  * Results:
  189.  *    A pointer to the summary bytes for this region or NIL if
  190.  *    there is not enought room.
  191.  *
  192.  * Side effects:
  193.  *
  194.  *----------------------------------------------------------------------
  195.  */
  196.  
  197. char *
  198. LfsSegSlowGrowSummary(segPtr, dataBlocksNeeded, sumBytesNeeded, addNewBlock)
  199.     register LfsSeg    *segPtr;    /* Segment of interest. */
  200.     int     dataBlocksNeeded;        /* Number of data blocks needed. */
  201.     int    sumBytesNeeded;            /* Number of summary bytes needed. */
  202.     Boolean addNewBlock;        /* Added a new block if necessary. */
  203. {
  204.     Lfs    *lfsPtr;
  205.     int     sumBytesLeft, blocksLeft, sumBlocks;
  206.  
  207.     /*
  208.      * Test the most common case first. Do the data and summary fit
  209.      * in the current configuration. 
  210.      */
  211.     sumBytesLeft = LfsSegSummaryBytesLeft(segPtr);
  212.     blocksLeft = LfsSegBlocksLeft(segPtr);
  213.     if ((blocksLeft >= dataBlocksNeeded) && (sumBytesLeft >= sumBytesNeeded)) {
  214.        return segPtr->curSummaryPtr;
  215.     }
  216.     /*
  217.      * Need to add a summary block. Bail if the user doesn't what it 
  218.      * or there is not enought room.
  219.      */
  220.     sumBlocks = 1;
  221.     if (!addNewBlock || (dataBlocksNeeded + sumBlocks > blocksLeft)) { 
  222.     return (char *) NIL;
  223.     }
  224.     lfsPtr = segPtr->lfsPtr;
  225.     /*
  226.      * Malloc a new summary buffer and add it to the segment.
  227.      */
  228.     AddNewSummaryBlock(segPtr);
  229.     return segPtr->curSummaryPtr;
  230. }
  231.  
  232. /*
  233.  *----------------------------------------------------------------------
  234.  *
  235.  * LfsSegSlowDiskAddress --
  236.  *
  237.  *    Compute the disk address of a LfsSegElement.
  238.  *
  239.  * Results:
  240.  *    The disk address of the element.
  241.  *
  242.  * Side effects:
  243.  *    None.
  244.  *
  245.  *----------------------------------------------------------------------
  246.  */
  247.  
  248. LfsDiskAddr
  249. LfsSegSlowDiskAddress(segPtr, segElementPtr)
  250.     register LfsSeg    *segPtr;     /* Segment of interest. */
  251.     LfsSegElement *segElementPtr; /* Segment element of interest. */
  252. {
  253.     int    elementNumber, blockOffset;
  254.     LfsDiskAddr diskAddress, newDiskAddr;
  255.     /*
  256.      * Check the common case that we are asking about the "current"
  257.      * element. 
  258.      */
  259.     elementNumber = segElementPtr - segPtr->segElementPtr;
  260.  
  261.     if (elementNumber == segPtr->curElement) {
  262.     blockOffset = segPtr->curBlockOffset;
  263.     } else {
  264.     int    i;
  265.     blockOffset = segPtr->startBlockOffset;
  266.     for (i = 0; i <= elementNumber; i++) {
  267.         blockOffset += segPtr->segElementPtr[i].lengthInBlocks;
  268.     }
  269.     }
  270.     LfsSegNumToDiskAddress(segPtr->lfsPtr, segPtr->logRange.current, 
  271.         &diskAddress);
  272.     blockOffset = LfsSegSizeInBlocks(segPtr->lfsPtr) - blockOffset;
  273.     LfsDiskAddrPlusOffset(diskAddress, blockOffset, &newDiskAddr);
  274.     return newDiskAddr;
  275. }
  276.  
  277. /*
  278.  *----------------------------------------------------------------------
  279.  *
  280.  * LfsSegSlowAddDataBuffer --
  281.  *
  282.  *    Add a LfsSegElement to a segment.
  283.  *
  284.  * Results:
  285.  *    A pointer to the LfsSegElement added. NIL if the object would not
  286.  *    fit.
  287.  *
  288.  * Side effects:
  289.  *    None.
  290.  *
  291.  *----------------------------------------------------------------------
  292.  */
  293.  
  294. LfsSegElement *
  295. LfsSegSlowAddDataBuffer(segPtr, blocks, bufferPtr, clientData)
  296.     register LfsSeg    *segPtr;  /* Segment to add to. */ 
  297.     int            blocks;      /* Size of buffer to add in blocks */
  298.     char   *bufferPtr;      /* Buffer to add. */
  299.     ClientData clientData; /* ClientData associated with this field. */
  300. {
  301.     LfsSegElement *elementPtr;
  302.  
  303.     if (segPtr->curBlockOffset + blocks > segPtr->curDataBlockLimit) {
  304.     return (LfsSegElement *) NIL;
  305.     }
  306.     segPtr->curElement++;
  307.     segPtr->curBlockOffset += blocks;
  308.  
  309.     elementPtr = segPtr->segElementPtr + segPtr->curElement;
  310.     elementPtr->lengthInBlocks = blocks;
  311.     elementPtr->clientData = clientData;
  312.     elementPtr->address    = bufferPtr;
  313.     segPtr->numElements = segPtr->curElement+1;
  314.     segPtr->numBlocks += blocks;
  315.     return elementPtr;
  316. }
  317.  
  318. /*
  319.  *----------------------------------------------------------------------
  320.  *
  321.  * InitSegmentMem --
  322.  *
  323.  *    Initialize the memory used by a file systems segment code.
  324.  *
  325.  * Results:
  326.  *    None.
  327.  *
  328.  * Side effects:
  329.  *    LfsSeg memories allocated.
  330.  *
  331.  *----------------------------------------------------------------------
  332.  */
  333. void
  334. InitSegmentMem(lfsPtr)
  335.     Lfs    *lfsPtr;
  336. {
  337.     LfsSeg    *segPtr;
  338.     int        maxSegElementSize;
  339.     int        i;
  340.     DevBlockDeviceHandle *handlePtr;
  341.  
  342.     /*
  343.      * Compute the maximum size of the seg element array. It can't be
  344.      * bigger than one element per block in segment.
  345.      */
  346.  
  347.     maxSegElementSize = LfsBytesToBlocks(lfsPtr,LfsSegSize(lfsPtr)) * 
  348.                     sizeof(LfsSegElement);
  349.     /*
  350.      * Fill in the fixed fields of the preallocated segments.
  351.      */
  352.     lfsPtr->segsInUse = 0;
  353.     lfsPtr->segs = (LfsSeg *) malloc(LFS_NUM_PREALLOC_SEGS *sizeof(LfsSeg));
  354.     for (i = 0; i < LFS_NUM_PREALLOC_SEGS; i++) { 
  355.     segPtr = lfsPtr->segs + i;
  356.     segPtr->lfsPtr = lfsPtr;
  357.     segPtr->segElementPtr = (LfsSegElement *) malloc(maxSegElementSize);
  358.     }
  359.     handlePtr = (DevBlockDeviceHandle *) lfsPtr->devicePtr->data;
  360.     if (handlePtr->maxTransferSize < LfsSegSize(lfsPtr)) { 
  361.     lfsPtr->writeBuffers[0] = malloc(handlePtr->maxTransferSize*2);
  362.     lfsPtr->writeBuffers[1] = lfsPtr->writeBuffers[0] + 
  363.                     handlePtr->maxTransferSize;
  364.     } else {
  365.     lfsPtr->writeBuffers[0] = malloc(LfsSegSize(lfsPtr));
  366.     lfsPtr->writeBuffers[1] = (char *) NIL;
  367.     }
  368.  
  369. }
  370.  
  371. /*
  372.  *----------------------------------------------------------------------
  373.  *
  374.  * FreeSegmentMem --
  375.  *
  376.  *    Free the memory used by a file systems segment code.
  377.  *
  378.  * Results:
  379.  *    None.
  380.  *
  381.  * Side effects:
  382.  *    LfsSeg structures freed.
  383.  *
  384.  *----------------------------------------------------------------------
  385.  */
  386. void
  387. FreeSegmentMem(lfsPtr)
  388.     Lfs    *lfsPtr;
  389. {
  390.     int i;
  391.     free(lfsPtr->writeBuffers[0]);
  392.     lfsPtr->segsInUse = 0;
  393.     for (i = 0; i < LFS_NUM_PREALLOC_SEGS; i++) { 
  394.     free((char *)(lfsPtr->segs[i].segElementPtr));
  395.     }
  396.     free((char *) (lfsPtr->segs));
  397.  
  398. }
  399.  
  400. /*
  401.  *----------------------------------------------------------------------
  402.  *
  403.  * AddNewSummaryBlock --
  404.  *
  405.  *  Add a summary block to a segment.
  406.  *
  407.  * Results:
  408.  *    None.
  409.  *
  410.  * Side effects:
  411.  *    A new summary block is malloc() and initialized.
  412.  *
  413.  *----------------------------------------------------------------------
  414.  */
  415. static void
  416. AddNewSummaryBlock(segPtr)
  417.     LfsSeg    *segPtr;    /* Seg to add block to. */
  418. {
  419.     LfsSegElement *sumBufferPtr;
  420.     LfsSegSummary *newSummaryPtr;
  421.     int          sumBytes;
  422.  
  423.     sumBytes = LfsBlockSize(segPtr->lfsPtr);
  424.     sumBufferPtr = LfsSegAddDataBuffer(segPtr, 1, malloc(sumBytes),
  425.                     (ClientData) NIL);
  426.     newSummaryPtr =  (LfsSegSummary *) sumBufferPtr->address;
  427.     newSummaryPtr->magic = LFS_SEG_SUMMARY_MAGIC;
  428.     newSummaryPtr->timestamp = LfsGetCurrentTimestamp(segPtr->lfsPtr);
  429.     newSummaryPtr->prevSeg = segPtr->logRange.prevSeg;
  430.     newSummaryPtr->nextSeg = segPtr->logRange.nextSeg;
  431.     newSummaryPtr->size = sizeof(LfsSegSummary);
  432.     newSummaryPtr->nextSummaryBlock = -1;
  433.  
  434.     if (segPtr->curSegSummaryPtr != (LfsSegSummary *) NIL) { 
  435.     /*
  436.      * This is not the first summary block in the segment.  Fixup the
  437.      * size of the last summary block and point it at the new one. 
  438.      */
  439.     segPtr->curSegSummaryPtr->size = segPtr->curSummaryPtr - 
  440.                     (char *) (segPtr->curSegSummaryPtr);
  441.     segPtr->curSegSummaryPtr->nextSummaryBlock = segPtr->curBlockOffset;
  442.     } 
  443.     segPtr->curSegSummaryPtr = newSummaryPtr;
  444.  
  445.     segPtr->curSummaryPtr = sumBufferPtr->address + sizeof(LfsSegSummary);
  446.     segPtr->curSummaryLimitPtr = sumBufferPtr->address + sumBytes;
  447. }
  448.  
  449. void
  450. CopySegToBuffer( segPtr, maxSize, bufferPtr, lenPtr)
  451.     LfsSeg    *segPtr;
  452.     int        maxSize;
  453.     char    *bufferPtr;
  454.     int        *lenPtr;
  455. {
  456.     int bytes, offset;
  457.     LfsSegElement *elementPtr;
  458.     Boolean full;
  459.  
  460.     *lenPtr = 0;
  461.     offset = 0;
  462.     full = FALSE;
  463.     while ((segPtr->curElement >= 0) && !full) {
  464.     elementPtr = segPtr->segElementPtr + segPtr->curElement;
  465.     bytes = LfsBlocksToBytes(segPtr->lfsPtr, 
  466.         elementPtr->lengthInBlocks - segPtr->curBlockOffset);
  467.     if (*lenPtr + bytes > maxSize) {
  468.         /*
  469.          * Element doesn't fit in this buffer. 
  470.          */
  471.         if (*lenPtr == maxSize) {
  472.         offset = 0;
  473.         } else { 
  474.         offset = LfsBytesToBlocks(segPtr->lfsPtr,(maxSize - *lenPtr));
  475.         }
  476.         bytes = LfsBlocksToBytes(segPtr->lfsPtr, offset);
  477.         full = TRUE;
  478.     } 
  479.     if (segPtr->curBlockOffset == 0) { 
  480.         bcopy(elementPtr->address, bufferPtr + *lenPtr, bytes);
  481.     } else {
  482.         bcopy(elementPtr->address + 
  483.            LfsBlocksToBytes(segPtr->lfsPtr,segPtr->curBlockOffset),
  484.           bufferPtr + *lenPtr, bytes);
  485.     }
  486.     *lenPtr += bytes;
  487.     if (full) {
  488.         segPtr->curBlockOffset += offset;
  489.     } else {
  490.         segPtr->curElement--;
  491.         segPtr->curBlockOffset = 0;
  492.     }
  493.     }
  494. }
  495.  
  496.  
  497. /*
  498.  *----------------------------------------------------------------------
  499.  *
  500.  * SegIoDoneProc --
  501.  *
  502.  *    This procedure is called when a sync block command started by 
  503.  *    WriteSegmentStart finished. It's calling sequence is 
  504.  *    defined by the call back caused by the Dev_BlockDeviceIO routine.
  505.  *
  506.  * Results:
  507.  *    None.
  508.  *
  509.  * Side effects:
  510.  *
  511.  *----------------------------------------------------------------------
  512.  */
  513.  
  514. static void
  515. SegIoDoneProc(requestPtr, status, amountTransferred)
  516.     DevBlockDeviceRequest    *requestPtr;
  517.     ReturnStatus status;
  518.     int    amountTransferred;
  519. {
  520.     LfsSeg    *segPtr = (LfsSeg *) (requestPtr->clientData);
  521.     DevBlockDeviceHandle *handlePtr;
  522.  
  523.     handlePtr = (DevBlockDeviceHandle *) segPtr->lfsPtr->devicePtr->data;
  524.     /*
  525.      * A pointer to the LfsSeg is passed as the clientData to this call.
  526.      * Start the new request if one is available. If this is the last
  527.      * request note the I/O as done.
  528.      */
  529.     MASTER_LOCK(&segPtr->ioMutex);
  530.     if (amountTransferred != requestPtr->bufferLen) {
  531.     status = VM_SHORT_WRITE;
  532.     }
  533.     if (status != SUCCESS) {
  534.     segPtr->ioReturnStatus = status;
  535.     }
  536.     requestPtr->startAddress = DEV_BYTES_PER_SECTOR * 
  537.                 LfsDiskAddrToOffset(segPtr->nextDiskAddress);
  538.     requestPtr->bufferLen = 0;
  539.     CopySegToBuffer(segPtr, handlePtr->maxTransferSize, requestPtr->buffer, 
  540.             &requestPtr->bufferLen);
  541.     segPtr->nextDiskAddress += requestPtr->bufferLen/DEV_BYTES_PER_SECTOR;
  542.     if (requestPtr->bufferLen == 0) { 
  543.     segPtr->requestActive--;
  544.     if (segPtr->requestActive == 0) {
  545.         segPtr->ioDone = TRUE;
  546.         Sync_MasterBroadcast(&segPtr->ioDoneWait);
  547.     }
  548.     } 
  549.     MASTER_UNLOCK(&segPtr->ioMutex);
  550.     if (requestPtr->bufferLen > 0) {
  551.     status = Dev_BlockDeviceIO(handlePtr, requestPtr);
  552.     if (status != SUCCESS) {
  553.         LfsError(segPtr->lfsPtr, status, "Can't start log write.\n");
  554.     }
  555.     }
  556.     return;
  557. }
  558.  
  559.  
  560. /*
  561.  *----------------------------------------------------------------------
  562.  *
  563.  * WriteSegmentStart --
  564.  *
  565.  *    Start a segment write to the log.
  566.  *
  567.  * Results:
  568.  *    SUCCESS if write complete. The ReturnStatus otherwise.
  569.  *
  570.  * Side effects:
  571.  *    None.
  572.  *
  573.  *----------------------------------------------------------------------
  574.  */
  575. static ReturnStatus
  576. WriteSegmentStart(segPtr) 
  577.     LfsSeg    *segPtr;    /* Segment to write. */
  578. {
  579.     Lfs    *lfsPtr = segPtr->lfsPtr;
  580.     int offset;
  581.     LfsDiskAddr  diskAddress;
  582.     ReturnStatus status = SUCCESS;
  583.     DevBlockDeviceHandle *handlePtr;
  584.     DevBlockDeviceRequest *requestPtr;
  585.  
  586.     Sync_SemInitDynamic(&(segPtr->ioMutex),"LfsSegIoMutex");
  587.     segPtr->ioDone = FALSE;
  588.     segPtr->ioReturnStatus = SUCCESS;
  589.  
  590.     if (SegIsEmpty(segPtr)) { 
  591.     /*
  592.      * The segment being written is empty so we don't have
  593.      * to write anytime. Just mark the I/O as done.
  594.      */
  595.     segPtr->ioDone = TRUE;
  596.     return SUCCESS;
  597.     }
  598.  
  599.     handlePtr = (DevBlockDeviceHandle *) lfsPtr->devicePtr->data;
  600.  
  601.     /*
  602.      * Writing to a segment nukes the segment cache.
  603.      */
  604.     if (lfsPtr->segCache.valid && 
  605.      (lfsPtr->segCache.segNum == segPtr->logRange.current)) {
  606.     lfsPtr->segCache.valid = FALSE;
  607.     }
  608.     LFS_STATS_INC(lfsPtr->stats.log.segWrites);
  609.  
  610.     LFS_STATS_ADD(lfsPtr->stats.log.wasteBlocks,
  611.                 segPtr->curDataBlockLimit - segPtr->curBlockOffset);
  612.     /*
  613.      * Compute the starting disk address of this I/O.
  614.      */
  615.     LfsSegNumToDiskAddress(lfsPtr, segPtr->logRange.current, &diskAddress);
  616.     offset = LfsSegSizeInBlocks(lfsPtr)    - segPtr->curBlockOffset;
  617.     LfsDiskAddrPlusOffset(diskAddress,offset, &segPtr->nextDiskAddress);
  618.  
  619.  
  620.     /*
  621.      * Fill in the request block fields that don't change between 
  622.      * requests.
  623.      */
  624.  
  625.     segPtr->bioreq[0].operation = segPtr->bioreq[1].operation = FS_WRITE;
  626.     segPtr->bioreq[0].startAddrHigh = segPtr->bioreq[1].startAddrHigh = 0;
  627.     segPtr->bioreq[0].doneProc = segPtr->bioreq[1].doneProc = SegIoDoneProc;
  628.     segPtr->bioreq[0].clientData = segPtr->bioreq[1].clientData = 
  629.                 (ClientData) segPtr;
  630.  
  631.     segPtr->curElement = segPtr->numElements-1;
  632.     segPtr->curBlockOffset = 0;
  633.     /*
  634.      * Start up the first two disk I/Os. 
  635.      */
  636.     requestPtr = segPtr->bioreq+0;
  637.     requestPtr->startAddress = DEV_BYTES_PER_SECTOR * 
  638.                 LfsDiskAddrToOffset(segPtr->nextDiskAddress);
  639.     requestPtr->buffer = lfsPtr->writeBuffers[0];
  640.     requestPtr->bufferLen = 0;
  641.     CopySegToBuffer(segPtr, handlePtr->maxTransferSize, requestPtr->buffer,
  642.         &requestPtr->bufferLen);
  643.     segPtr->nextDiskAddress += requestPtr->bufferLen/DEV_BYTES_PER_SECTOR;
  644.     segPtr->requestActive = 1;
  645.  
  646.     /*
  647.      * Disk request number 2.
  648.      */
  649.     requestPtr = segPtr->bioreq+1;
  650.     requestPtr->startAddress = DEV_BYTES_PER_SECTOR * 
  651.                 LfsDiskAddrToOffset(segPtr->nextDiskAddress);
  652.     requestPtr->buffer = lfsPtr->writeBuffers[1];
  653.     requestPtr->bufferLen = 0;
  654.     CopySegToBuffer(segPtr, handlePtr->maxTransferSize, requestPtr->buffer,
  655.             &requestPtr->bufferLen);
  656.     segPtr->nextDiskAddress += requestPtr->bufferLen/DEV_BYTES_PER_SECTOR;
  657.     if (requestPtr->bufferLen > 0) { 
  658.     segPtr->requestActive = 2;
  659.     } else {
  660.     segPtr->requestActive = 1;
  661.     }
  662.     status = Dev_BlockDeviceIO(handlePtr, segPtr->bioreq);
  663.     if (status != SUCCESS) {
  664.     LfsError(lfsPtr, status, "Can't start disk log write.\n");
  665.     }
  666.     if (requestPtr->bufferLen > 0) {
  667.     status = Dev_BlockDeviceIO(handlePtr, segPtr->bioreq+1);
  668.     if (status != SUCCESS) {
  669.         LfsError(lfsPtr, status, "Can't start disk log write.\n");
  670.     }
  671.     }
  672.  
  673.  
  674.     LFS_STATS_ADD(lfsPtr->stats.log.blocksWritten, segPtr->numBlocks);
  675.     LFS_STATS_ADD(lfsPtr->stats.log.bytesWritten, segPtr->activeBytes);
  676.     return status;
  677. }
  678.  
  679. /*
  680.  *----------------------------------------------------------------------
  681.  *
  682.  * WriteSegmentFinish --
  683.  *
  684.  *    Wait for a segment write to finish.
  685.  *
  686.  * Results:
  687.  *    SUCCESS if write complete. The ReturnStatus otherwise.
  688.  *
  689.  * Side effects:
  690.  *    None.
  691.  *
  692.  *----------------------------------------------------------------------
  693.  */
  694. static ReturnStatus
  695. WriteSegmentFinish(segPtr) 
  696.     LfsSeg    *segPtr;    /* Segment to wait for. */
  697. {
  698.     ReturnStatus status;
  699.     MASTER_LOCK((&segPtr->ioMutex));
  700.     while (segPtr->ioDone == FALSE) { 
  701.     Sync_MasterWait((&segPtr->ioDoneWait),(&segPtr->ioMutex),FALSE);
  702.     }
  703.     status = segPtr->ioReturnStatus;
  704.     MASTER_UNLOCK((&segPtr->ioMutex));
  705.  
  706.     return status;
  707. }
  708.  
  709.  
  710. /*
  711.  *----------------------------------------------------------------------
  712.  *
  713.  * WriteDoneNotify --
  714.  *
  715.  *    Notify others that a log write has finished and another may be
  716.  *    started.
  717.  *
  718.  * Results:
  719.  *    None
  720.  *
  721.  * Side effects:
  722.  *    None.
  723.  *
  724.  *----------------------------------------------------------------------
  725.  */
  726.  
  727. static void
  728. WriteDoneNotify(lfsPtr)
  729.     Lfs    *lfsPtr;
  730. {
  731.     LOCK_MONITOR;
  732.     lfsPtr->activeFlags &= ~LFS_WRITE_ACTIVE;
  733.     Sync_Broadcast(&lfsPtr->writeWait);
  734.     UNLOCK_MONITOR;
  735. }
  736.  
  737. /*
  738.  *----------------------------------------------------------------------
  739.  *
  740.  * CreateSegmentToWrite --
  741.  *
  742.  *    Create an LfsSeg structure describing an empty segment to be 
  743.  *    filled in by the callback routines.
  744.  *
  745.  * Results:
  746.  *    A pointer to a lfsSeg.
  747.  *
  748.  * Side effects:
  749.  *    None.
  750.  *
  751.  *----------------------------------------------------------------------
  752.  */
  753. static LfsSeg *
  754. CreateSegmentToWrite(lfsPtr, dontBlock) 
  755.     Lfs    *lfsPtr;        /* For which file system. */
  756.     Boolean        dontBlock;    /* Don't wait for segment. */
  757. {
  758.     LfsSeg    *segPtr;
  759.     LfsSegLogRange    segLogRange;
  760.     int        startBlock;
  761.     ReturnStatus status;
  762.  
  763.     LOCK_MONITOR;
  764.  
  765.     /*
  766.      * Wait for previous writes to finish.
  767.      */
  768.     while (lfsPtr->activeFlags & LFS_WRITE_ACTIVE) {
  769.     Sync_Wait(&lfsPtr->writeWait, FALSE);
  770.     }
  771.  
  772.     do { 
  773.     status = LfsGetLogTail(lfsPtr, dontBlock, &segLogRange, &startBlock);
  774.     if ((status == FS_WOULD_BLOCK) && !dontBlock) {
  775.         LFS_STATS_INC(lfsPtr->stats.log.cleanSegWait);
  776.         lfsPtr->activeFlags |= LFS_CLEANSEGWAIT_ACTIVE;
  777.         Sync_Wait(&lfsPtr->cleanSegmentsWait, FALSE);
  778.     } 
  779.     } while ((status == FS_WOULD_BLOCK) && !dontBlock);
  780.  
  781.     if (status == SUCCESS) { 
  782.     lfsPtr->activeFlags |= LFS_WRITE_ACTIVE;
  783.     segPtr = GetSegStruct(lfsPtr, &segLogRange, startBlock, (char *) NIL);
  784.     } else {
  785.     segPtr = (LfsSeg *) NIL;
  786.     }
  787.     UNLOCK_MONITOR;
  788.     return segPtr;
  789. }
  790.  
  791. /*
  792.  *----------------------------------------------------------------------
  793.  *
  794.  * RewindCurPtrs --
  795.  *
  796.  *    Rewind the current pointers of a segment to the start of the first
  797.  *    segment.
  798.  *
  799.  * Results:
  800.  *    None.
  801.  *
  802.  * Side effects:
  803.  *    None.
  804.  *
  805.  *----------------------------------------------------------------------
  806.  */
  807. static void
  808. RewindCurPtrs(segPtr)
  809.     LfsSeg    *segPtr;
  810. {
  811.     segPtr->curSegSummaryPtr = (LfsSegSummary *) 
  812.                 (segPtr->segElementPtr[0].address);
  813.     segPtr->curSummaryHdrPtr = (LfsSegSummaryHdr *) 
  814.                 (segPtr->curSegSummaryPtr + 1);
  815.     segPtr->curElement = 1;
  816.  
  817.     segPtr->curBlockOffset = segPtr->startBlockOffset+1;
  818.     segPtr->curDataBlockLimit = segPtr->curSummaryHdrPtr->numDataBlocks;
  819.     segPtr->curSummaryPtr = (char *) (segPtr->curSummaryHdrPtr + 1);
  820.     segPtr->curSummaryLimitPtr = (char *) (segPtr->curSummaryHdrPtr) +
  821.             segPtr->curSummaryHdrPtr->lengthInBytes;
  822.  
  823. }
  824.  
  825. /*
  826.  *----------------------------------------------------------------------
  827.  *
  828.  * DestorySegStruct --
  829.  *
  830.  *    Destory an LfsSeg structure.
  831.  *
  832.  * Results:
  833.  *    None.
  834.  *
  835.  * Side effects:
  836.  *    None.
  837.  *
  838.  *----------------------------------------------------------------------
  839.  */
  840.  
  841. static void
  842. DestorySegStruct(segPtr)
  843.     LfsSeg    *segPtr;    /* Segment to Destory. */
  844. {
  845.  
  846.     int num;
  847.  
  848.     num = segPtr - segPtr->lfsPtr->segs;
  849.     segPtr->lfsPtr->segsInUse  &= ~(1 << num);
  850. }
  851.  
  852.  
  853. /*
  854.  *----------------------------------------------------------------------
  855.  *
  856.  * GetSegStruct --
  857.  *
  858.  *    Allocate an LfsSeg structure.
  859.  *
  860.  * Results:
  861.  *    A lfsSeg structure
  862.  *
  863.  * Side effects:
  864.  *    None.
  865.  *
  866.  *----------------------------------------------------------------------
  867.  */
  868.  
  869. static LfsSeg *
  870. GetSegStruct(lfsPtr, segLogRangePtr, startBlockOffset, memPtr)
  871.     Lfs    *lfsPtr;    /* File system. */
  872.     LfsSegLogRange *segLogRangePtr; /* Log range of segment. */
  873.     int           startBlockOffset; /* Starting block offset into segment */
  874.     char       *memPtr;         /* Memory allocated for segment. */
  875. {
  876.     int        i;
  877.     LfsSeg    *segPtr;
  878.  
  879.     segPtr = (LfsSeg *) NIL;
  880.     for (i = 0; i < LFS_NUM_PREALLOC_SEGS; i++) { 
  881.     if (!(lfsPtr->segsInUse & (1 << i))) {
  882.         lfsPtr->segsInUse |= (1 << i);
  883.         segPtr = lfsPtr->segs + i;
  884.         break;
  885.     }
  886.     }
  887.     if (segPtr == (LfsSeg *) NIL) {
  888.     panic("GetSegStruct out of segment structures.\n");
  889.     }
  890.     segPtr->memPtr = memPtr;
  891.     segPtr->logRange = *segLogRangePtr;
  892.     segPtr->numElements = 0;
  893.     segPtr->numBlocks = 0;
  894.     segPtr->startBlockOffset = startBlockOffset;
  895.     segPtr->activeBytes = 0;
  896.     segPtr->timeOfLastWrite = 0;
  897.     segPtr->curSegSummaryPtr = (LfsSegSummary *) NIL;
  898.     segPtr->curSummaryHdrPtr = (LfsSegSummaryHdr *) NIL;
  899.     segPtr->curElement = -1;
  900.     segPtr->curBlockOffset = segPtr->startBlockOffset;
  901.     segPtr->curDataBlockLimit = LfsSegSizeInBlocks(lfsPtr);
  902.     segPtr->curSummaryPtr = (char *) NIL;
  903.     segPtr->curSummaryLimitPtr = (char *) NIL;
  904.  
  905.     return segPtr;
  906. }
  907.  
  908.  
  909. /*
  910.  *----------------------------------------------------------------------
  911.  *
  912.  * DoInCallBacks --
  913.  *
  914.  *    Perform the call backs that take segments as input.
  915.  *
  916.  * Results:
  917.  *    TRUE if the segment is full. False otherwise.
  918.  *
  919.  * Side effects:
  920.  *    None.
  921.  *
  922.  *----------------------------------------------------------------------
  923.  */
  924. static Boolean
  925. DoInCallBacks(type, segPtr, flags, sizePtr, numCacheBlocksPtr, clientDataPtr) 
  926.     enum CallBackType type;    /* Type of segment operation. */
  927.     LfsSeg    *segPtr;    /* Segment to fill in or out. */
  928.     int        flags;        /* Flags used during checkpoint. */
  929.     int            *sizePtr; /* Size of checkpoint buffer or segment cleaned. */
  930.     int *numCacheBlocksPtr;
  931.     ClientData *clientDataPtr;
  932.  
  933. {
  934.     int    moduleType, size, numCacheBlocks, next;
  935.     Boolean error = FALSE;
  936.     char     *endSummaryBlockPtr;
  937.     LfsSegElement *bufferPtr;
  938.  
  939.     /*
  940.      * We're doing a pass over an existing segment such as during a
  941.      * cleaning IN phase or a WRITE_DONE callback. Initialize the 
  942.      * moduleType from the summary region. 
  943.      */
  944.     endSummaryBlockPtr = (char *)segPtr->curSegSummaryPtr + 
  945.             segPtr->curSegSummaryPtr->size;
  946.     while(!error) { 
  947.     while (((char *)segPtr->curSummaryHdrPtr < endSummaryBlockPtr) &&
  948.             (segPtr->curSummaryHdrPtr->lengthInBytes > 0))  {
  949.         LfsSegIoInterface *intPtr;
  950.     
  951.         moduleType = segPtr->curSummaryHdrPtr->moduleType;
  952.         segPtr->curSummaryLimitPtr = ((char *)(segPtr->curSummaryHdrPtr) + 
  953.                 segPtr->curSummaryHdrPtr->lengthInBytes);
  954.         segPtr->curSummaryPtr = (char *) (segPtr->curSummaryHdrPtr + 1);
  955.         intPtr = lfsSegIoInterfacePtrs[moduleType];
  956.         switch (type) {
  957.         case SEG_CLEAN_IN:
  958.         size = 0;
  959.         numCacheBlocks = 0;
  960.         error = intPtr->clean(segPtr, &size, &numCacheBlocks, 
  961.                 clientDataPtr + moduleType);
  962. #ifdef lint
  963.         error = LfsDescMapClean(segPtr, &size, &numCacheBlocks, 
  964.                 clientDataPtr + moduleType);
  965.         error = LfsSegUsageClean(segPtr, &size, &numCacheBlocks, 
  966.                 clientDataPtr + moduleType);
  967.         error = LfsFileLayoutClean(segPtr, &size, &numCacheBlocks, 
  968.                 clientDataPtr + moduleType);
  969. #endif /* lint */
  970.         *sizePtr += size;
  971.         *numCacheBlocksPtr += numCacheBlocks;
  972.         break;
  973.         case SEG_WRITEDONE: {
  974.         intPtr->writeDone(segPtr, flags, clientDataPtr + moduleType);
  975. #ifdef lint
  976.         LfsDescMapWriteDone(segPtr, flags,  clientDataPtr + moduleType);
  977.         LfsSegUsageWriteDone(segPtr, flags, clientDataPtr + moduleType);
  978.         LfsFileLayoutWriteDone(segPtr, flags, clientDataPtr + moduleType);
  979. #endif /* lint */
  980.         break;
  981.          }
  982.          default:
  983.          panic("lfsSeg.c: Bad case statement\n");
  984.          }
  985.          if (error) {
  986.             break;
  987.          }
  988.          segPtr->curBlockOffset += segPtr->curSummaryHdrPtr->numDataBlocks;
  989.          /*
  990.           * Skip to the next summary header. 
  991.           */
  992.          segPtr->curSummaryHdrPtr = 
  993.             (LfsSegSummaryHdr *) segPtr->curSummaryLimitPtr;
  994.      }
  995.      if (error) {
  996.         break;
  997.      }
  998.      /*
  999.       * If we ran over the end of current summary block move on to 
  1000.       * the next.
  1001.       */
  1002.       next = segPtr->curSegSummaryPtr->nextSummaryBlock;
  1003.       if (type == SEG_WRITEDONE) {
  1004.         /*
  1005.          * Free up any memory we allocated during the layout
  1006.          */
  1007.         LFS_STATS_ADD(segPtr->lfsPtr->stats.log.summaryBytesWritten,
  1008.                 segPtr->curSegSummaryPtr->size);
  1009.         LFS_STATS_INC(segPtr->lfsPtr->stats.log.summaryBlocksWritten);
  1010.         free((char *) segPtr->curSegSummaryPtr);
  1011.       }
  1012.           if (next == -1) {
  1013.         /*
  1014.          * No more summary bytes for this segment.
  1015.          */
  1016.         break;
  1017.        }
  1018.        bufferPtr = LfsSegGetBufferPtr(segPtr);
  1019.        segPtr->curSegSummaryPtr = (LfsSegSummary *) bufferPtr->address;
  1020.        segPtr->curSummaryHdrPtr = (LfsSegSummaryHdr *)
  1021.                         (segPtr->curSegSummaryPtr + 1);
  1022.        endSummaryBlockPtr = (char *)segPtr->curSegSummaryPtr + 
  1023.             segPtr->curSegSummaryPtr->size;
  1024.        bufferPtr++;
  1025.        LfsSegSetBufferPtr(segPtr, bufferPtr);
  1026.        segPtr->curBlockOffset = next;
  1027.     }
  1028.    return error;
  1029. }
  1030.  
  1031.  
  1032. /*
  1033.  *----------------------------------------------------------------------
  1034.  *
  1035.  * DoOutCallBacks --
  1036.  *
  1037.  *    Perform the call backs for output to segments.
  1038.  *
  1039.  * Results:
  1040.  *    TRUE if the segment is full. False otherwise.
  1041.  *
  1042.  * Side effects:
  1043.  *    None.
  1044.  *
  1045.  *----------------------------------------------------------------------
  1046.  */
  1047. static Boolean
  1048. DoOutCallBacks(type, segPtr, flags, checkPointPtr, sizePtr, clientDataPtr) 
  1049.     enum CallBackType type;    /* Type of segment operation. */
  1050.     LfsSeg    *segPtr;    /* Segment to fill in or out. */
  1051.     int        flags;        /* Flags used during checkpoint. */
  1052.     char    *checkPointPtr; /* Checkpoint buffer. */
  1053.     int            *sizePtr; /* Size of checkpoint buffer or segment cleaned. */
  1054.     ClientData *clientDataPtr;
  1055.  
  1056. {
  1057.     int    moduleType, startOffset;
  1058.     Boolean full;
  1059.     char    *summaryPtr, *endSummaryPtr;
  1060.     int        newStartBlockOffset;
  1061.     LfsCheckPointRegion    *segUsageCheckpointRegionPtr;
  1062.  
  1063.     full = FALSE;
  1064.     segUsageCheckpointRegionPtr = (LfsCheckPointRegion *) NIL;
  1065.     for(moduleType = 0; moduleType < LFS_MAX_NUM_MODS; ) {
  1066.     LfsSegIoInterface *intPtr = lfsSegIoInterfacePtrs[moduleType];
  1067.     /*
  1068.      * Filling in a segment, be sure that there is enought
  1069.      * room for the LfsSegSummaryHdr.
  1070.      */
  1071.     summaryPtr = LfsSegSlowGrowSummary(segPtr, 1,
  1072.         sizeof(LfsSegSummaryHdr) + MIN_SUMMARY_REGION_SIZE, TRUE);
  1073.     if (summaryPtr == (char *) NIL) {
  1074.         full = TRUE;
  1075.         break;
  1076.     }
  1077.     segPtr->curSummaryHdrPtr = (LfsSegSummaryHdr *)  summaryPtr;
  1078.     LfsSegSetSummaryPtr(segPtr, summaryPtr + sizeof(LfsSegSummaryHdr));
  1079.     startOffset = segPtr->curBlockOffset;
  1080.     switch (type) {
  1081.     case SEG_CLEAN_OUT:
  1082.     case SEG_LAYOUT: 
  1083.         full = intPtr->layout(segPtr, flags, clientDataPtr + moduleType);
  1084. #ifdef lint
  1085.         full = LfsSegUsageLayout(segPtr, flags, clientDataPtr + moduleType);
  1086.         full = LfsDescMapLayout(segPtr, flags, clientDataPtr + moduleType);
  1087.         full = LfsFileLayoutProc(segPtr, flags, clientDataPtr + moduleType);
  1088. #endif /* lint */
  1089.         break;
  1090.     case SEG_CHECKPOINT: {
  1091.         int    size;
  1092.         LfsCheckPointRegion    *regionPtr;
  1093.         regionPtr = (LfsCheckPointRegion *) checkPointPtr;
  1094.         size = 0;
  1095.         full = intPtr->checkpoint(segPtr, flags, (char *)(regionPtr + 1),
  1096.                      &size, clientDataPtr + moduleType);
  1097. #ifdef lint
  1098.         full = LfsDescMapCheckpoint(segPtr, flags, (char *)(regionPtr + 1),
  1099.                      &size, clientDataPtr + moduleType);
  1100.         full = LfsSegUsageCheckpoint(segPtr, flags, (char *)(regionPtr + 1),
  1101.                      &size, clientDataPtr + moduleType);
  1102.         full = LfsFileLayoutCheckpoint(segPtr, flags,
  1103.                 (char *)(regionPtr + 1), &size,
  1104.                 clientDataPtr + moduleType);
  1105. #endif /* lint */
  1106.         if (size > 0) {
  1107.         if (moduleType == LFS_SEG_USAGE_MOD) {
  1108.             segUsageCheckpointRegionPtr = regionPtr;
  1109.         }
  1110.         regionPtr->type = moduleType;
  1111.         regionPtr->size = size + sizeof(LfsCheckPointRegion);
  1112.         *sizePtr += regionPtr->size;
  1113.         checkPointPtr += regionPtr->size;
  1114.         }
  1115.         break;
  1116.      }
  1117.      default:
  1118.          panic("lfsSeg.c: Bad case statement\n");
  1119.      }
  1120.      /*
  1121.       * If the callback added data to the segment, fill in the summary 
  1122.       * header. 
  1123.       */
  1124.      endSummaryPtr = LfsSegGetSummaryPtr(segPtr); 
  1125.      if ((startOffset != segPtr->curBlockOffset) ||
  1126.          ((summaryPtr + sizeof(LfsSegSummaryHdr)) != endSummaryPtr)) {
  1127.         segPtr->curSummaryHdrPtr->moduleType = moduleType;
  1128.         segPtr->curSummaryHdrPtr->lengthInBytes = endSummaryPtr - 
  1129.                 (char *) summaryPtr;
  1130.         segPtr->curSummaryHdrPtr->numDataBlocks =  
  1131.                 segPtr->curBlockOffset - startOffset;
  1132.      } else {
  1133.          LfsSegSetSummaryPtr(segPtr, summaryPtr);
  1134.      }
  1135.      /*
  1136.       * If we didn't fill the segment in skip to the next module.
  1137.       */
  1138.      if (full) { 
  1139.         if (LfsSegSummaryBytesLeft(segPtr) > MIN_SUMMARY_REGION_SIZE) {
  1140.         break;
  1141.         }
  1142.      } else {
  1143.         moduleType++;
  1144.      }
  1145.    }
  1146.    /*
  1147.     * Update the size of the last summary block and cap off this segment. 
  1148.     */
  1149.    segPtr->curSegSummaryPtr->size = segPtr->curSummaryPtr - 
  1150.                     (char *) segPtr->curSegSummaryPtr;
  1151.  
  1152.    newStartBlockOffset = -1;
  1153.    if (!full) {
  1154.     if (SegIsEmpty(segPtr)) { 
  1155.         /*
  1156.          * The segment is totally empty.  We don't need to write
  1157.          * this one yet.
  1158.          */
  1159.         LFS_STATS_INC(segPtr->lfsPtr->stats.log.emptyWrites);
  1160.         newStartBlockOffset = segPtr->startBlockOffset;
  1161.     } else if ((segPtr->curDataBlockLimit -  segPtr->curBlockOffset) > 
  1162.                segPtr->lfsPtr->superBlock.usageArray.wasteBlocks) { 
  1163.         /*
  1164.          * If this is considered to be a partial segment write add the
  1165.          * summary block we needed.
  1166.          */
  1167.         AddNewSummaryBlock(segPtr);
  1168.         newStartBlockOffset = segPtr->curBlockOffset-1;
  1169.         LFS_STATS_INC(segPtr->lfsPtr->stats.log.partialWrites);
  1170.     }
  1171.    }
  1172.  
  1173.    LfsSetLogTail(segPtr->lfsPtr, &segPtr->logRange, newStartBlockOffset, 
  1174.                 segPtr->activeBytes, segPtr->timeOfLastWrite);  
  1175.    if (segUsageCheckpointRegionPtr != (LfsCheckPointRegion *) NIL) {
  1176.        LfsSegUsageCheckpointUpdate(segPtr->lfsPtr, 
  1177.             (char *) (segUsageCheckpointRegionPtr + 1),
  1178.             segUsageCheckpointRegionPtr->size - 
  1179.                     sizeof(LfsCheckPointRegion));
  1180.     }
  1181.  
  1182.     return full;
  1183. }
  1184.  
  1185.  
  1186.  
  1187.  
  1188. /*
  1189.  *----------------------------------------------------------------------
  1190.  *
  1191.  * SegmentCleanProc --
  1192.  *
  1193.  *    Proc_CallFunc procedure for cleaning segments. The routine
  1194.  *    reads the segments into memory by calling the "Clean IN"
  1195.  *    routines and writes the data out by callin the "Clean OUT"
  1196.  *    routines.
  1197.  *
  1198.  * Results:
  1199.  *    None.
  1200.  *
  1201.  * Side effects:
  1202.  *    Segments are mark as clean.    
  1203.  *
  1204.  *----------------------------------------------------------------------
  1205.  */
  1206.  
  1207.  
  1208. static void
  1209. SegmentCleanProc(clientData, callInfoPtr)
  1210.     ClientData      clientData;    /* File system to clean blocks in */
  1211.     Proc_CallInfo *callInfoPtr;         /* Not used. */
  1212.  
  1213. {
  1214.     register Lfs *lfsPtr = (Lfs *) clientData;       
  1215.     int        numSegsToClean, maxNumSegsToClean;
  1216.     LfsSegList    *segs;
  1217.     int        cacheBlocksInUse, segNo, numSegsCleaned, segsGen;
  1218.     LfsSeg     *segPtr;
  1219.     Boolean    full;
  1220.     ReturnStatus    status;
  1221.     ClientData        clientDataArray[LFS_MAX_NUM_MODS];
  1222.     int            numWritten, numCleaned, totalSize, cacheBlocksReserved;
  1223.     int            minNeededToClean, totalNumWritten, maxAvailToWrite;
  1224.     int            totalNumCleaned;
  1225.     Boolean        error;
  1226.     Boolean        checkPoint;
  1227.     char        *memPtr;
  1228.  
  1229. #define    MAX_CLEANING_PASSES    5
  1230. #define    MAX_NUM_SEGS_TO_CLEAN    2048
  1231.  
  1232.     lfsPtr->cleanerProcPtr = Proc_GetCurrentProc();
  1233.     maxNumSegsToClean = lfsPtr->usageArray.checkPoint.numDirty;
  1234.     if (maxNumSegsToClean > MAX_NUM_SEGS_TO_CLEAN) {
  1235.     maxNumSegsToClean = MAX_NUM_SEGS_TO_CLEAN;
  1236.     }
  1237.     segs = (LfsSegList *) malloc(sizeof(LfsSegList) * maxNumSegsToClean);
  1238.     /*
  1239.      * Reserve the memory and cache blocks needed for cleaning.
  1240.      */
  1241.     LfsMemReserve(lfsPtr, &cacheBlocksReserved, &memPtr);
  1242.     numSegsToClean = LfsGetSegsToClean(lfsPtr, maxNumSegsToClean, segs,
  1243.                 &minNeededToClean, &maxAvailToWrite);
  1244.     /*
  1245.      * Loop until the there are less than two segments to clean.
  1246.      */
  1247.     numSegsCleaned = 0;
  1248.     totalNumWritten = totalNumCleaned = 0;
  1249.     while (numSegsToClean > 1) {
  1250.     LFS_STATS_INC(lfsPtr->stats.cleaning.getSegsRequests);
  1251.     LFS_STATS_ADD(lfsPtr->stats.cleaning.segsToClean, numSegsToClean);
  1252.         printf("%s: Cleaning started - deficit %d segs\n", lfsPtr->name,
  1253.             minNeededToClean);
  1254.     if (minNeededToClean < lfsMinNumberToClean) {
  1255.         minNeededToClean = lfsMinNumberToClean;
  1256.     }
  1257.     segNo = 0;
  1258.     segsGen = 0;
  1259.     do {
  1260.         int j;
  1261.         /*
  1262.          * Reading in segments to clean.
  1263.          */
  1264.         for (j = 0; j < LFS_MAX_NUM_MODS; j++) {
  1265.         clientDataArray[j] = (ClientData) NIL;
  1266.         }
  1267.         totalSize = 0;      /* Total size in bytes of data cleaned. */
  1268.         cacheBlocksInUse = 0; /* Number of cache blocks in use. */
  1269.         numCleaned = 0;
  1270.         for (; segNo < numSegsToClean; segNo++) {
  1271.         int size, numCacheBlocksUsed, bytesGenerated;
  1272.         /*
  1273.          * If this segment will no fit in the space reserved in the
  1274.          * cache then end cleaning. Also end cleaning if we 
  1275.          * used up all the segments that we can write. Also end
  1276.          * cleaning if we have someone waiting for us and 
  1277.          * we have generated enough to let them proceed.
  1278.          */
  1279.         bytesGenerated = numCleaned * LfsSegSize(lfsPtr) - totalSize;
  1280.         if ((cacheBlocksInUse + segs[segNo].activeBytes/FS_BLOCK_SIZE >
  1281.                             cacheBlocksReserved) ||
  1282.            ((totalSize + segs[segNo].activeBytes) > 
  1283.                 LfsSegSize(lfsPtr)*maxAvailToWrite) ||
  1284.            (((lfsPtr->activeFlags & LFS_CHECKPOINTWAIT_ACTIVE) ||
  1285.              lfsPtr->writeBackActive) &&
  1286.             (bytesGenerated > LfsSegSize(lfsPtr)*minNeededToClean))
  1287.               ) {
  1288.             break;
  1289.         }
  1290.         size = 0;
  1291.         numCacheBlocksUsed = 0;
  1292. #ifdef ERROR_CHECK
  1293.         if (TRUE) {
  1294. #else
  1295.         if (segs[segNo].activeBytes > 0) { 
  1296. #endif /* ERROR_CHECK */
  1297.             segPtr = CreateSegmentToClean(lfsPtr, segs[segNo].segNumber,
  1298.                 memPtr);
  1299.             error = DoInCallBacks(SEG_CLEAN_IN, segPtr, 0, &size,
  1300.                     &numCacheBlocksUsed, clientDataArray);
  1301.             if (!error && (segs[segNo].activeBytes == 0) && (size != 0)) {
  1302.             printf("Warning: Segment %d cleaned found wrong active bytes %d != %d\n", segs[segNo].segNumber, size, segs[segNo].activeBytes);
  1303.             }
  1304.     
  1305.             DestorySegStruct(segPtr);
  1306.         } else {
  1307.             error = FALSE;
  1308.             size = 0;
  1309.         }
  1310.         if (error) {
  1311.             LFS_STATS_ADD(lfsPtr->stats.cleaning.readErrors, 1);
  1312.             segs[segNo].segNumber = -1;
  1313.         } else { 
  1314.             if (size == 0) {
  1315.             LFS_STATS_INC(lfsPtr->stats.cleaning.readEmpty);
  1316.             } else {
  1317.             int bucket = (size*LFS_STATS_CDIST_BUCKETS)
  1318.                         / LfsSegSize(lfsPtr);
  1319.             if (bucket >= LFS_STATS_CDIST_BUCKETS) {
  1320.                 bucket = (LFS_STATS_CDIST_BUCKETS - 1);
  1321.             }
  1322.             lfsPtr->stats.cleaningDist[bucket]++;
  1323.             }
  1324.             numCleaned++;
  1325.         }
  1326.         totalSize += size;
  1327.         cacheBlocksInUse += numCacheBlocksUsed;
  1328.         }
  1329.         numSegsCleaned = segNo;
  1330.         LFS_STATS_ADD(lfsPtr->stats.cleaning.segReads,numCleaned);
  1331.         LFS_STATS_ADD(lfsPtr->stats.cleaning.bytesCleaned,totalSize);
  1332.         LFS_STATS_ADD(lfsPtr->stats.cleaning.cacheBlocksUsed, cacheBlocksInUse);
  1333.         /*
  1334.          * Write out segments cleaned.
  1335.          */
  1336.         numWritten = 0;
  1337.         if (totalSize > 0) { 
  1338.         full = TRUE;
  1339.         while (full) {
  1340.             segPtr = CreateSegmentToWrite(lfsPtr, TRUE);
  1341.             if (segPtr == (LfsSeg *) NIL) {
  1342.             LfsError(lfsPtr, FAILURE, "Ran out of clean segments during cleaning.\n");
  1343.             }
  1344.             full = DoOutCallBacks(SEG_CLEAN_OUT, segPtr, 
  1345.                     LFS_CLEANING_LAYOUT, (char *) NIL,
  1346.                     (int *) NIL, clientDataArray);
  1347.     
  1348.             status = WriteSegmentStart(segPtr);
  1349.             if (status == SUCCESS) {
  1350.             status = WriteSegmentFinish(segPtr);
  1351.             }
  1352.             if (status != SUCCESS) {
  1353.             LfsError(lfsPtr, status, "Can't write segment to log\n");
  1354.             }
  1355.             RewindCurPtrs(segPtr);
  1356.             (void) DoInCallBacks(SEG_WRITEDONE, segPtr, LFS_CLEANING_LAYOUT,
  1357.                     (int *) NIL, (int *) NIL,  clientDataArray);
  1358.             WriteDoneNotify(lfsPtr);
  1359.             numWritten++;
  1360.             LFS_STATS_ADD(lfsPtr->stats.cleaning.blocksWritten, 
  1361.                     segPtr->numBlocks);
  1362.             LFS_STATS_ADD(lfsPtr->stats.cleaning.bytesWritten, 
  1363.                     segPtr->activeBytes);
  1364.             LFS_STATS_ADD(lfsPtr->stats.cleaning.segWrites, numWritten);
  1365.             DestorySegStruct(segPtr);
  1366.         }
  1367.         }
  1368.         /*
  1369.          * We keep cleaning segments until we have generated
  1370.          * enough segments to get us above a certain threashold.
  1371.          * Becareful not to use all available segments. In more
  1372.          * detail, loop while:
  1373.          * 1) We haven't generated enough segments already.
  1374.          * 2) We haven't cleaned all the segments we are given.
  1375.          * 3) We haven't written out as many segments as possible.
  1376.          * 4) If someone is waiting for us we have cleaned the 
  1377.          *    minimum possible to allow them to proceed.
  1378.          */
  1379.         segsGen += (numCleaned - numWritten);
  1380.         totalNumWritten += numWritten;
  1381.         totalNumCleaned += numCleaned;
  1382.     } while ((segsGen <= minNeededToClean) && (segNo < numSegsToClean) &&
  1383.          (totalNumWritten < maxAvailToWrite) &&
  1384.           !((lfsPtr->activeFlags & LFS_CHECKPOINTWAIT_ACTIVE) &&
  1385.             (segsGen >= lfsMinNumberToClean)));
  1386.  
  1387.     status = LfsCheckPointFileSystem(lfsPtr, 
  1388.             LFS_CHECKPOINT_NOSEG_WAIT|LFS_CHECKPOINT_CLEANER);
  1389.     if (status != SUCCESS) {
  1390.         LfsError(lfsPtr, status, "Can't checkpoint after cleaning.\n");
  1391.     }
  1392.     if (numSegsCleaned > 0) { 
  1393.         lfsPtr->segCache.valid = FALSE;
  1394.         LfsMarkSegsClean(lfsPtr, numSegsCleaned, segs);
  1395.         LOCK_MONITOR;
  1396.         lfsPtr->activeFlags &= ~LFS_CLEANSEGWAIT_ACTIVE;
  1397.         Sync_Broadcast(&lfsPtr->cleanSegmentsWait);
  1398.         UNLOCK_MONITOR;
  1399.     }
  1400.     printf("%s: Cleaned %d segments in %d segments\n", 
  1401.             lfsPtr->name, totalNumCleaned, totalNumWritten);
  1402.     numSegsToClean = LfsGetSegsToClean(lfsPtr, maxNumSegsToClean, segs,
  1403.              &minNeededToClean, &maxAvailToWrite);
  1404.     if (minNeededToClean == 0) {
  1405.         break;
  1406.     }
  1407.     }
  1408.     free((char *)segs);
  1409.     lfsPtr->segCache.valid = FALSE;
  1410.     LfsMemRelease(lfsPtr, cacheBlocksReserved, memPtr);
  1411.  
  1412.     LOCK_MONITOR;
  1413.     /*  
  1414.      * Release the flags that mark us as an active cleaner process for
  1415.      * this file system.
  1416.      * If someone is waiting for us to checkpoint.
  1417.      */
  1418.     lfsPtr->activeFlags &= ~LFS_CLEANER_ACTIVE;
  1419.     lfsPtr->cleanerProcPtr = (Proc_ControlBlock *) NIL;
  1420.     checkPoint = (lfsPtr->activeFlags & LFS_CHECKPOINTWAIT_ACTIVE);
  1421.     UNLOCK_MONITOR;
  1422.  
  1423.     if (checkPoint) { 
  1424.     (void) LfsCheckPointFileSystem(lfsPtr, 0);
  1425.     }
  1426.  
  1427. }
  1428.  
  1429.  
  1430. static LfsSeg *
  1431. CreateSegmentToClean(lfsPtr, segNumber, cleaningMemPtr)
  1432.     Lfs    *lfsPtr;    /* File system of segment. */
  1433.     int    segNumber;    /* Segment number to clean. */
  1434.     char *cleaningMemPtr; /* Memory to use for cleaning. */
  1435. {
  1436.     LfsSeg        *segPtr;
  1437.     int            segSize;
  1438.     ReturnStatus    status;
  1439.     LfsSegLogRange    logRange;
  1440.     LfsSegSummary    *segSumPtr;
  1441.     LfsDiskAddr        diskAddress;
  1442.  
  1443.     logRange.prevSeg = -1;
  1444.     logRange.current = segNumber;
  1445.     logRange.nextSeg = -1;
  1446.  
  1447.     /*
  1448.      * Get a LfsSeg structure.
  1449.      */
  1450.     lfsPtr->segCache.valid = FALSE;
  1451.     segPtr = GetSegStruct(lfsPtr, &logRange, 0, cleaningMemPtr);
  1452.  
  1453.     /*
  1454.      * Read in the segment in memory.
  1455.      */
  1456.     segSize = LfsSegSize(lfsPtr);
  1457.  
  1458.     LfsSegNumToDiskAddress(lfsPtr, segNumber, &diskAddress);
  1459.     status = LfsReadBytes(lfsPtr, diskAddress, segSize, cleaningMemPtr);
  1460.     if (status != SUCCESS) {
  1461.     LfsError(lfsPtr, status, "Can't read segment to clean.\n");
  1462.     return (LfsSeg *) NIL;
  1463.     }
  1464.     lfsPtr->segCache.segNum = segNumber;
  1465.     LfsSegNumToDiskAddress(lfsPtr, segNumber, 
  1466.         &lfsPtr->segCache.startDiskAddress);
  1467.     LfsSegNumToDiskAddress(lfsPtr, segNumber+1, 
  1468.         &lfsPtr->segCache.endDiskAddress);
  1469.     lfsPtr->segCache.memPtr = cleaningMemPtr;
  1470.     lfsPtr->segCache.valid = TRUE;
  1471.  
  1472.     segSumPtr = (LfsSegSummary *)
  1473.         (cleaningMemPtr + segSize - LfsBlockSize(lfsPtr));
  1474.     while (1) { 
  1475.     segPtr->segElementPtr[segPtr->numElements].lengthInBlocks = 0;
  1476.     segPtr->segElementPtr[segPtr->numElements].address = (char *) segSumPtr;
  1477.     segPtr->segElementPtr[segPtr->numElements].clientData = 
  1478.                 (ClientData) NIL;
  1479.     segPtr->numElements++;
  1480.  
  1481.     LFS_STATS_INC(lfsPtr->stats.cleaning.summaryBlocksRead);
  1482.     if (segSumPtr->nextSummaryBlock == -1) {
  1483.         break;
  1484.     }
  1485.     segSumPtr = (LfsSegSummary *) 
  1486.             LfsSegFetchBytes(segPtr, segSumPtr->nextSummaryBlock,
  1487.                 LfsBlockSize(lfsPtr));
  1488.     }
  1489.     RewindCurPtrs(segPtr);
  1490.     return segPtr;
  1491. }
  1492.  
  1493. /*
  1494.  *----------------------------------------------------------------------
  1495.  *
  1496.  * LfsSegAttach --
  1497.  *
  1498.  *    Call the attach routines all the segment I/O modules.
  1499.  *
  1500.  * Results:
  1501.  *    SUCCESS if everything when well.
  1502.  *
  1503.  * Side effects:
  1504.  *    None.
  1505.  *
  1506.  *----------------------------------------------------------------------
  1507.  */
  1508.  
  1509. ReturnStatus
  1510. LfsSegAttach(lfsPtr, checkPointPtr, checkPointSize)
  1511.     Lfs        *lfsPtr;    /* File system being attached. */
  1512.     char        *checkPointPtr; /* Latest checkpoint header. */
  1513.     int        checkPointSize; /* Size of the checkpoint buffer. */
  1514. {
  1515.     int        moduleType;
  1516.     char    *limitPtr;
  1517.     LfsCheckPointRegion *regionPtr;
  1518.     ReturnStatus    status;
  1519.     LfsSegIoInterface    *segIoPtr;
  1520.  
  1521.     lfsPtr->segCache.valid = FALSE;
  1522.  
  1523.     limitPtr = checkPointPtr + checkPointSize;
  1524.     for (moduleType = 0; moduleType < LFS_MAX_NUM_MODS; moduleType++) {
  1525.     regionPtr = (LfsCheckPointRegion *) checkPointPtr;
  1526.     segIoPtr = lfsSegIoInterfacePtrs[moduleType];
  1527.     if ((checkPointPtr < limitPtr) && (regionPtr->type == moduleType)) { 
  1528.         checkPointPtr += regionPtr->size;
  1529.         status = segIoPtr->attach(lfsPtr, 
  1530.                 (int)(regionPtr->size - sizeof(*regionPtr)),
  1531.                 (char *) (regionPtr+1));
  1532. #ifdef lint
  1533.         status = LfsDescMapAttach(lfsPtr, 
  1534.                 (int)(regionPtr->size - sizeof(*regionPtr)),
  1535.                 (char *) (regionPtr+1));
  1536.         status = LfsFileLayoutAttach(lfsPtr, 
  1537.                 (int)(regionPtr->size - sizeof(*regionPtr)),
  1538.                 (char *) (regionPtr+1));
  1539.         status = LfsSegUsageAttach(lfsPtr, 
  1540.                 (int)(regionPtr->size - sizeof(*regionPtr)),
  1541.                 (char *) (regionPtr+1));
  1542.  
  1543. #endif /* lint */
  1544.     } else {
  1545.         status = segIoPtr->attach(lfsPtr, 0, (char *)NIL);
  1546. #ifdef lint
  1547.         status = LfsDescMapAttach(lfsPtr, 0, (char *)NIL);
  1548.         status = LfsFileLayoutAttach(lfsPtr, 0, (char *)NIL);
  1549.         status = LfsSegUsageAttach(lfsPtr, 0, (char *)NIL);
  1550. #endif /* lint */
  1551.     }
  1552.     if (status != SUCCESS) {
  1553.         LfsError(lfsPtr, status, "Can't attach module");
  1554.         break;
  1555.     }
  1556.     }
  1557.     if (status == SUCCESS) {
  1558.     InitSegmentMem(lfsPtr);
  1559.     return status;
  1560.     }
  1561.     /*
  1562.      * XXX - Back out of error here by shutting down all module.
  1563.      */
  1564.     return status;
  1565. }
  1566.  
  1567. /*
  1568.  *----------------------------------------------------------------------
  1569.  *
  1570.  * LfsSegCheckPoint --
  1571.  *
  1572.  *    Call the checkpoint routines all the segment I/O modules.
  1573.  *
  1574.  * Results:
  1575.  *    SUCCESS if everything when well.
  1576.  *
  1577.  * Side effects:
  1578.  *    None.
  1579.  *
  1580.  *----------------------------------------------------------------------
  1581.  */
  1582.  
  1583. ReturnStatus
  1584. LfsSegCheckPoint(lfsPtr, flags, checkPointPtr, checkPointSizePtr)
  1585.     Lfs              *lfsPtr;        /* File system to checkpoint. */
  1586.     int            flags;        /* Flags to checkpoint operation. */
  1587.     char        *checkPointPtr;    /* Checkpoint area to be filled in.*/
  1588.     int            *checkPointSizePtr; /* Size of checkpoint buffer. */
  1589. {
  1590.     Boolean    full = TRUE;
  1591.     LfsSeg    *segPtr;
  1592.     ClientData        clientDataArray[LFS_MAX_NUM_MODS];
  1593.     int            i;
  1594.     ReturnStatus    status= SUCCESS;
  1595.  
  1596.     LOCK_MONITOR;
  1597.  
  1598.     /*
  1599.      * Wait for the cleaner not to be active unless we are called from the 
  1600.      * cleaner, the detach code, or the timer callback.
  1601.      */
  1602.     if (lfsPtr->activeFlags & LFS_CLEANER_ACTIVE) {
  1603.     if (flags & LFS_CHECKPOINT_TIMER) {
  1604.         /*
  1605.          * Since the cleaner does checkpoints frequently, we can safely
  1606.          * ignore TIMER checkpoints.
  1607.          */
  1608.         (*checkPointSizePtr) = -1;
  1609.         UNLOCK_MONITOR;
  1610.         return SUCCESS;
  1611.         }
  1612.     if (!(flags & (LFS_CHECKPOINT_DETACH|LFS_CHECKPOINT_CLEANER))) {
  1613.         /*
  1614.          * Unless the checkpoint is from the cleaner or the detach 
  1615.          * code we simply wait for a checkpoint to complete and 
  1616.          * return.
  1617.          */
  1618.         if (!(lfsPtr->activeFlags & LFS_CHECKPOINTWAIT_ACTIVE)) {
  1619.         lfsPtr->activeFlags |= LFS_CHECKPOINTWAIT_ACTIVE;
  1620.         }
  1621.         while (lfsPtr->activeFlags & LFS_CHECKPOINTWAIT_ACTIVE) { 
  1622.         Sync_Wait(&lfsPtr->checkPointWait, FALSE);
  1623.         }
  1624.         (*checkPointSizePtr) = -1;
  1625.         UNLOCK_MONITOR;
  1626.         return SUCCESS;
  1627.     } 
  1628.     }
  1629.     /*
  1630.      * Wait for any currently running checkpoint to finish.
  1631.      * TIMER checkpoints again can be ignored and cleaner checkpoint can
  1632.      * run in parallel.
  1633.      */
  1634.     if (!(flags & LFS_CHECKPOINT_CLEANER)) { 
  1635.     while (lfsPtr->activeFlags & LFS_CHECKPOINT_ACTIVE) {
  1636.         if (flags & LFS_CHECKPOINT_TIMER) {
  1637.         (*checkPointSizePtr) = -1;
  1638.         UNLOCK_MONITOR;
  1639.         return SUCCESS;
  1640.         }
  1641.         Sync_Wait(&lfsPtr->checkPointWait, FALSE);
  1642.     }
  1643.     lfsPtr->activeFlags |= LFS_SYNC_CHECKPOINT_ACTIVE;
  1644.     } else {
  1645.     lfsPtr->activeFlags |= LFS_CLEANER_CHECKPOINT_ACTIVE;
  1646.     }
  1647.  
  1648.     /*
  1649.      * Wait for any directory log operations to finish.
  1650.      */
  1651.     while (lfsPtr->dirModsActive > 0) {
  1652.     Sync_Wait(&lfsPtr->checkPointWait, FALSE);
  1653.     }
  1654.     /*
  1655.      * If we a detatching the file system wait for any cleaners to exit.
  1656.      */
  1657.     if (flags & LFS_CHECKPOINT_DETACH) {
  1658.     lfsPtr->activeFlags |= LFS_SHUTDOWN_ACTIVE;
  1659.     while (lfsPtr->activeFlags & LFS_CLEANER_ACTIVE) {
  1660.         Time time;
  1661.         time.seconds = 1;
  1662.         time.microseconds = 0;
  1663.         Sync_WaitTime(time);
  1664.     }
  1665.     }
  1666.     LFS_STATS_INC(lfsPtr->stats.checkpoint.count);
  1667.     UNLOCK_MONITOR;
  1668.  
  1669.     if (flags & LFS_CHECKPOINT_DETACH) {
  1670.     LfsStopWriteBack(lfsPtr);
  1671.     }
  1672.  
  1673.     for (i = 0; i < LFS_MAX_NUM_MODS; i++) {
  1674.     clientDataArray[i] = (ClientData) NIL;
  1675.     }
  1676.     while (full) {
  1677.     segPtr = CreateSegmentToWrite(lfsPtr, 
  1678.             ((flags & LFS_CHECKPOINT_NOSEG_WAIT) != 0));
  1679.     if (segPtr == (LfsSeg *) NIL) {
  1680.         LfsError(lfsPtr, FAILURE, "Ran out of clean segments during cleaner checkpoint.\n");
  1681.     }
  1682.     *checkPointSizePtr = 0;
  1683.     full = DoOutCallBacks(SEG_CHECKPOINT, segPtr, flags,
  1684.                 checkPointPtr, checkPointSizePtr, clientDataArray);
  1685.     LFS_STATS_INC(lfsPtr->stats.checkpoint.segWrites);
  1686.     LFS_STATS_ADD(lfsPtr->stats.checkpoint.blocksWritten,
  1687.                     segPtr->numBlocks);
  1688.     LFS_STATS_ADD(lfsPtr->stats.checkpoint.bytesWritten,
  1689.                 segPtr->activeBytes);
  1690.     status = WriteSegmentStart(segPtr);
  1691.     if (status == SUCCESS) {
  1692.         status = WriteSegmentFinish(segPtr);
  1693.     }
  1694.     if (status != SUCCESS) {
  1695.         LfsError(lfsPtr, status, "Can't write segment to log\n");
  1696.     }
  1697.     RewindCurPtrs(segPtr);
  1698.     (void) DoInCallBacks(SEG_WRITEDONE, segPtr, flags, (int *) NIL, (int *) NIL,
  1699.                 clientDataArray);
  1700.     WriteDoneNotify(lfsPtr);
  1701.         DestorySegStruct(segPtr);
  1702.     }
  1703.     return status;
  1704.  
  1705. }
  1706.  
  1707. /*
  1708.  *----------------------------------------------------------------------
  1709.  *
  1710.  * LfsSegCheckPointDone --
  1711.  *
  1712.  *    Mark a checkpoint as done.
  1713.  *
  1714.  * Results:
  1715.  *    None.
  1716.  *
  1717.  * Side effects:
  1718.  *    None.
  1719.  *
  1720.  *----------------------------------------------------------------------
  1721.  */
  1722.  
  1723. void
  1724. LfsSegCheckPointDone(lfsPtr, flags)
  1725.     Lfs    *lfsPtr;
  1726.     int    flags;
  1727. {
  1728.     LOCK_MONITOR;
  1729.     lfsPtr->numDirtyBlocks = 0;
  1730. #ifdef ERROR_CHECK
  1731.     { 
  1732.     int numBlocks, numDirty;
  1733.     Fscache_CountBlocks(rpc_SpriteID, lfsPtr->domainPtr->domainNumber,
  1734.                 &numBlocks, &numDirty);
  1735.     if (((flags & LFS_CHECKPOINT_DETACH) && numDirty) || (numDirty > 1)) {
  1736.         printf("DirtyBlocks (%d) after a checkpoint\n", numDirty);
  1737.     }
  1738.     }
  1739. #endif
  1740.     if (flags & LFS_CHECKPOINT_CLEANER) {
  1741.     lfsPtr->activeFlags &= 
  1742.         ~(LFS_CLEANER_CHECKPOINT_ACTIVE|LFS_CHECKPOINTWAIT_ACTIVE|
  1743.           LFS_CLEANSEGWAIT_ACTIVE);
  1744.     Sync_Broadcast(&lfsPtr->cleanSegmentsWait)
  1745.     } else { 
  1746.     lfsPtr->activeFlags &= 
  1747.         ~(LFS_SYNC_CHECKPOINT_ACTIVE|LFS_CHECKPOINTWAIT_ACTIVE);
  1748.     }
  1749.     Sync_Broadcast(&lfsPtr->checkPointWait);
  1750.     UNLOCK_MONITOR;
  1751. }
  1752.  
  1753. /*
  1754.  *----------------------------------------------------------------------
  1755.  *
  1756.  * LfsSegDetach --
  1757.  *
  1758.  *    Call a shutdown time on an LFS file system.
  1759.  *
  1760.  * Results:
  1761.  *    SUCCESS if everything when well.
  1762.  *
  1763.  * Side effects:
  1764.  *    None.
  1765.  *
  1766.  *----------------------------------------------------------------------
  1767.  */
  1768.  
  1769. ReturnStatus
  1770. LfsSegDetach(lfsPtr)
  1771.     Lfs              *lfsPtr;        /* File system to checkpoint. */
  1772. {
  1773.  
  1774.     int    moduleType;
  1775.     LfsSegIoInterface    *segIoPtr;
  1776.     ReturnStatus status = SUCCESS;
  1777.  
  1778.     for (moduleType = 0; moduleType < LFS_MAX_NUM_MODS; moduleType++) {
  1779.     segIoPtr = lfsSegIoInterfacePtrs[moduleType];
  1780.     status = segIoPtr->detach(lfsPtr);
  1781. #ifdef lint
  1782.     status = LfsDescMapDetach(lfsPtr);
  1783.     status = LfsFileLayoutDetach(lfsPtr);
  1784.     status = LfsSegUsageDetach(lfsPtr);
  1785. #endif 
  1786.     }
  1787.     FreeSegmentMem(lfsPtr);
  1788.     return status;
  1789.  
  1790. }
  1791.  
  1792. /*
  1793.  *----------------------------------------------------------------------
  1794.  *
  1795.  * LfsWaitForCheckPoint --
  1796.  *
  1797.  *    Wait for a checkpoint to complete on a file system.
  1798.  *
  1799.  * Results:
  1800.  *    None.
  1801.  *
  1802.  * Side effects:
  1803.  *    None.
  1804.  *
  1805.  *----------------------------------------------------------------------
  1806.  */
  1807. void
  1808. LfsWaitForCheckPoint(lfsPtr) 
  1809.     Lfs    *lfsPtr;
  1810. {
  1811.     LOCK_MONITOR;
  1812.     while (lfsPtr->activeFlags & LFS_CHECKPOINT_ACTIVE) {
  1813.     Sync_Wait(&lfsPtr->checkPointWait, FALSE);
  1814.     }
  1815.     UNLOCK_MONITOR;
  1816. }
  1817.  
  1818. /*
  1819.  *----------------------------------------------------------------------
  1820.  *
  1821.  * LfsWaitForCleanSegments --
  1822.  *
  1823.  *    Ensure that there is enough clean segments to write a
  1824.  *    dirty cache block being added to the system. Also
  1825.  *    besure that a checkpoint is not active.
  1826.  *
  1827.  * Results:
  1828.  *    None.
  1829.  *
  1830.  * Side effects:
  1831.  *    None.
  1832.  *
  1833.  *----------------------------------------------------------------------
  1834.  */
  1835.  
  1836.  
  1837. void
  1838. LfsWaitForCleanSegments(lfsPtr)
  1839.     Lfs    *lfsPtr;
  1840. {
  1841.     LOCK_MONITOR;
  1842.     lfsPtr->numDirtyBlocks++;
  1843.     while ((lfsPtr->activeFlags & LFS_CHECKPOINT_ACTIVE) ||
  1844.         !LfsSegUsageEnoughClean(lfsPtr, 
  1845.             lfsPtr->numDirtyBlocks * FS_BLOCK_SIZE)) {
  1846.     if (!(lfsPtr->activeFlags & LFS_CHECKPOINTWAIT_ACTIVE)) {
  1847.         lfsPtr->activeFlags |= LFS_CHECKPOINTWAIT_ACTIVE;
  1848.     }
  1849.     Sync_Wait(&lfsPtr->checkPointWait, FALSE);
  1850.     }
  1851.     UNLOCK_MONITOR;
  1852. }
  1853.  
  1854.